/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package scm.inventoryControl.session.stateless;

import crm.salesOrderProcessing.entity.DeliveryOrderEntity;
import crm.salesOrderProcessing.entity.ProductEntity;
import crm.salesOrderProcessing.entity.SalesOrderEntity;
import scm.inventoryControl.entity.ProductBatchRecordEntity;
import scm.inventoryControl.entity.ProductInventoryLevelEntity;
import java.util.List;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import scm.inventoryControl.entity.PackingOrderEntity;
import scm.inventoryControl.entity.PickingOrderEntity;
import scm.inventoryControl.entity.RMInventoryLevelEntity;
import scm.inventoryControl.entity.ShippingOrderEntity;

/**
 *
 * @author TM
 */
@Stateless
@LocalBean
public class InventoryControlSessionBean {

    @PersistenceContext
    private EntityManager em;
    private ProductBatchRecordEntity newProductBatchRecord,oriProductBatchRecord;
    private ProductInventoryLevelEntity productInventoryLevel;
    private List<ProductBatchRecordEntity> records;
    private List<ProductBatchRecordEntity> targetedRecords;
     
    public List<DeliveryOrderEntity> getDeliveryOrders(){
         Query query = em.createQuery("SELECT d FROM DeliveryOrderEntity d WHERE d.parentSalesOrder.statusId = 500");
         
       return query.getResultList();
    }
    
    public List<ProductInventoryLevelEntity> getAllProductInventories() {
       Query query = em.createQuery("SELECT sl FROM ProductInventoryLevelEntity sl");
       return query.getResultList();
  }
    public List<RMInventoryLevelEntity> getAllRawMaterialInventories(){
       Query query = em.createQuery("SELECT rl FROM RWInventoryLevelEntity rl");
       return query.getResultList(); 
    }
    
    public List<ProductBatchRecordEntity> getAllProductRecords(){
           Query query = em.createQuery("SELECT sl FROM ProductBatchRecordEntity sl");
       return query.getResultList();
    }
    
    public void reserveProduct(SalesOrderEntity salesOrder){
        for(int i=0;i<salesOrder.getSalesOrderLineItems().size();i++){
            reserveProductForEachLineItem(salesOrder,salesOrder.getSalesOrderLineItems().get(i).getProduct().getProductName(),salesOrder.getSalesOrderLineItems().get(i).getQuantity());
        }
    }
    
    private void reserveProductForEachLineItem(SalesOrderEntity salesOrder,String productName, int requiredQuantity) throws NoResultException {//reserve product based on FIFO of product record
          Query query = em.createQuery("SELECT n FROM ProductBatchRecordEntity n WHERE n.productInventoryLevel = :inInventoryLevel Order by n.manufactureDate ");
          query.setParameter("inInventoryLevel", getInventoryByProductName(productName));
          int tempQuantity=requiredQuantity;
            setRecords((List<ProductBatchRecordEntity>)query.getResultList());
            int i=0;
            while(tempQuantity>0 && i<getRecords().size()){
             oriProductBatchRecord=getRecords().get(i);
             if(oriProductBatchRecord.getQuantity()>tempQuantity){ //the record can fulfill the order
                  newProductBatchRecord=new ProductBatchRecordEntity();
                  newProductBatchRecord.setQuantity(oriProductBatchRecord.getQuantity()-tempQuantity);
                  
                  oriProductBatchRecord.setQuantity(tempQuantity);
                  oriProductBatchRecord.setSalesOrder(salesOrder);
                  oriProductBatchRecord.setReserved(true);
                  em.merge(oriProductBatchRecord);
                  
                  newProductBatchRecord.setManufactureDate(oriProductBatchRecord.getManufactureDate());
                  newProductBatchRecord.setProductInventoryLevel(oriProductBatchRecord.getProductInventoryLevel());
                  newProductBatchRecord.setWarehouseLocation(oriProductBatchRecord.getWarehouseLocation());
                   
                  em.persist(newProductBatchRecord);
             }//end of if   
            else { 
                 oriProductBatchRecord.setReserved(true);
                 oriProductBatchRecord.setSalesOrder(salesOrder);
                 em.merge(oriProductBatchRecord);
             }
              tempQuantity=tempQuantity-oriProductBatchRecord.getQuantity();
              i++;
            }//end of while
            //update inventory level->increase reserved inventory
            getInventoryByProductName(productName).setReservedQty(getInventoryByProductName(productName).getReservedQty()+requiredQuantity);
              //update inventory level->decrese current inventory
             getInventoryByProductName(productName).setCurrentLevel(getInventoryByProductName(productName).getCurrentLevel()-requiredQuantity);
        }
    
    public boolean isPassATPCheck(String productName, int quantity){
        if(quantity<getCurrentInventoryLevel(productName))
                return true;
        else return false;
    }
   
    public int getCurrentInventoryLevel(String productName){
        return getInventoryByProductName(productName).getCurrentLevel();
    }
    
    public ProductInventoryLevelEntity getInventoryByProductName(String productName){
        //get product by name first
        Query query = em.createQuery("SELECT u FROM ProductEntity u WHERE u.productName = :inName");
        query.setParameter("inName", productName);
        ProductEntity product=null;
        product=(ProductEntity)query.getSingleResult();
        //get inventory by product
        Query query2 = em.createQuery("SELECT m FROM ProductInventoryLevelEntity m WHERE m.product = :inProduct");
        query2.setParameter("inProduct", product);
        return (ProductInventoryLevelEntity)query2.getSingleResult();
    }
     

    public void saveProductRecord(ProductBatchRecordEntity productBatchRecord){
        em.persist(productBatchRecord);
        //System.out.println("$$$$$$$$$$$$$$$$$Batch qty"+productBatchRecord.getQuantity());
        //System.out.println("current Lvl before add"+productBatchRecord.getProductInventoryLevel().getCurrentLevel());
       //adjustInventoryLevel(productBatchRecord);
        //increase current inventory level and decrease incoming level;
       ;
    }
    
    public void adjustInventoryLevel(ProductBatchRecordEntity productBatchRecord){
        
        ProductBatchRecordEntity productBatchRecordEntity = em.find(ProductBatchRecordEntity.class, productBatchRecord.getId());
       
        productBatchRecordEntity.getProductInventoryLevel().setCurrentLevel( productBatchRecordEntity.getProductInventoryLevel().getCurrentLevel()+productBatchRecordEntity.getQuantity());
       // System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%% set current level"+ (productBatchRecord.getProductInventoryLevel().getCurrentLevel()+productBatchRecord.getQuantity()));
        productBatchRecordEntity.getProductInventoryLevel().setIncomingQty( productBatchRecordEntity.getProductInventoryLevel().getIncomingQty()-productBatchRecordEntity.getQuantity());
        // System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%% set incoming level"+  (productBatchRecord.getProductInventoryLevel().getIncomingQty()-productBatchRecord.getQuantity()));
      
        //merge
      //  System.out.println("current Lvl before merge"+productBatchRecord.getProductInventoryLevel().getCurrentLevel());
        em.merge(productBatchRecordEntity.getProductInventoryLevel());
        em.flush(); 
    }
    
    public void savePickingOrder(PickingOrderEntity pickingOrder){
        em.persist(pickingOrder);
    }
     public void savePackingOrder(PackingOrderEntity packingOrder){
        em.persist(packingOrder);
    }
      public void saveShippingOrder(ShippingOrderEntity shippingOrder){
        em.persist(shippingOrder);
    }
            

    public ProductBatchRecordEntity getProductBatchRecord() {
        return newProductBatchRecord;
    }

    public void setProductBatchRecord(ProductBatchRecordEntity productBatchRecord) {
        this.newProductBatchRecord = productBatchRecord;
    }

    public ProductInventoryLevelEntity getProductInventoryLevel() {
        return productInventoryLevel;
    }

    public void setProductInventoryLevel(ProductInventoryLevelEntity productInventoryLevel) {
        this.productInventoryLevel = productInventoryLevel;
    }

    public List<ProductBatchRecordEntity> getRecords() {
        return records;
    }

    public void setRecords(List<ProductBatchRecordEntity> records) {
        this.records = records;
    }

    public List<ProductBatchRecordEntity> getTargetedRecords() {
        return targetedRecords;
    }

    public void setTargetedRecords(List<ProductBatchRecordEntity> targetedRecords) {
        this.targetedRecords = targetedRecords;
    }

    public ProductBatchRecordEntity getOriProductBatchRecord() {
        return oriProductBatchRecord;
    }

    public void setOriProductBatchRecord(ProductBatchRecordEntity oriProductBatchRecord) {
        this.oriProductBatchRecord = oriProductBatchRecord;
    }



    
     
    
}
